#include "oled.h"
#include "stdlib.h"
#include "../hardware/io.h"
#include "sys_timer.h"

void OLED_ColorTurn(uint8_t i)
{
	if (i == 0)
	{
		OLED_WR_Byte(0xA6, OLED_CMD);
	}
	if (i == 1)
	{
		OLED_WR_Byte(0xA7, OLED_CMD);
	}
}

void OLED_DisplayTurn(uint8_t i)
{
	if (i == 0)
	{
		OLED_WR_Byte(0xC8, OLED_CMD);
		OLED_WR_Byte(0xA1, OLED_CMD);
	}
	if (i == 1)
	{
		OLED_WR_Byte(0xC0, OLED_CMD);
		OLED_WR_Byte(0xA0, OLED_CMD);
	}
}

void OLED_DisPlay_On(void)
{
	OLED_WR_Byte(0x8D, OLED_CMD);
	OLED_WR_Byte(0x14, OLED_CMD);
	OLED_WR_Byte(0xAF, OLED_CMD);
}

void OLED_DisPlay_Off(void)
{
	OLED_WR_Byte(0x8D, OLED_CMD);
	OLED_WR_Byte(0x10, OLED_CMD);
	OLED_WR_Byte(0xAE, OLED_CMD);
}

void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
	uint8_t i;
	if (cmd)
		OLED_DC_Set();
	else
		OLED_DC_Clr();
	OLED_CS_Clr();
	for (i = 0; i < 8; i++)
	{
		OLED_SCL_Clr();
		if (dat & 0x80)
			OLED_SDA_Set();
		else
			OLED_SDA_Clr();
		OLED_SCL_Set();
		dat <<= 1;
	}
	OLED_CS_Set();
	OLED_DC_Set();
}

void OLED_Clear(void)
{
	uint8_t i, n;
	for (i = 0; i < 8; i++)
	{
		OLED_WR_Byte(0xb0 + i, OLED_CMD);
		OLED_WR_Byte(0x10, OLED_CMD);
		OLED_WR_Byte(0x00, OLED_CMD);
		for (n = 0; n < 128; n++)
		{
			OLED_WR_Byte(0x00, OLED_DATA);
		}
	}
}

void OLED_address(uint8_t x, uint8_t y)
{
	OLED_WR_Byte(0xb0 + y, OLED_CMD);
	OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
	OLED_WR_Byte((x & 0x0f), OLED_CMD);
}

void OLED_Display_128x64(uint8_t *dp)
{
	uint8_t i, j;
	for (i = 0; i < 8; i++)
	{
		OLED_address(0, i);
		for (j = 0; j < 128; j++)
		{
			OLED_WR_Byte(*dp, OLED_DATA);
			dp++;
		}
	}
}

void OLED_Display_16x16(uint8_t x, uint8_t y, uint8_t *dp)
{
	uint8_t i, j;
	for (j = 0; j < 2; j++)
	{
		OLED_address(x, y);
		for (i = 0; i < 16; i++)
		{
			OLED_WR_Byte(*dp, OLED_DATA);
			dp++;
		}
		y++;
	}
}

void OLED_Display_8x16(uint8_t x, uint8_t y, uint8_t *dp)
{
	uint8_t i, j;
	for (j = 0; j < 2; j++)
	{
		OLED_address(x, y);
		for (i = 0; i < 8; i++)
		{
			OLED_WR_Byte(*dp, OLED_DATA);
			dp++;
		}
		y++;
	}
}

void OLED_Display_5x7(uint8_t x, uint8_t y, uint8_t *dp)
{
	uint8_t i;
	OLED_address(x, y);
	for (i = 0; i < 6; i++)
	{
		OLED_WR_Byte(*dp, OLED_DATA);
		dp++;
	}
}

void Send_Command_to_ROM(uint8_t dat)
{
	uint8_t i;
	for (i = 0; i < 8; i++)
	{
		OLED_SCL_Clr();
		if (dat & 0x80)
		{
			OLED_SDA_Set();
		}
		else
		{
			OLED_SDA_Clr();
		}
		dat <<= 1;
		OLED_SCL_Set();
	}
}

uint8_t Get_data_from_ROM(void)
{
	uint8_t i, read = 0;
	for (i = 0; i < 8; i++)
	{
		OLED_SCL_Clr();
		read <<= 1;
		if (OLED_READ_FS0())
		{
			read++;
		}
		OLED_SCL_Set();
	}
	return read;
}

void OLED_get_data_from_ROM(uint8_t addrHigh, uint8_t addrMid, uint8_t addrLow, uint8_t *pbuff, uint8_t DataLen)
{
	uint8_t i;
	OLED_ROM_CS_Clr();
	Send_Command_to_ROM(0x03);
	Send_Command_to_ROM(addrHigh);
	Send_Command_to_ROM(addrMid);
	Send_Command_to_ROM(addrLow);
	for (i = 0; i < DataLen; i++)
	{
		*(pbuff + i) = Get_data_from_ROM();
	}
	OLED_ROM_CS_Set();
}

uint32_t fontaddr = 0;
void OLED_Display_GB2312_string(uint8_t x, uint8_t y, const char *text)
{
	uint8_t i = 0;
	uint8_t addrHigh, addrMid, addrLow;
	uint8_t fontbuf[32];
	while (text[i] > 0x00)
	{
		if ((text[i] >= 0xb0) && (text[i] <= 0xf7) && (text[i + 1] >= 0xa1))
		{
			fontaddr = (text[i] - 0xb0) * 94;
			fontaddr += (text[i + 1] - 0xa1) + 846;
			fontaddr = fontaddr * 32;

			addrHigh = (fontaddr & 0xff0000) >> 16;
			addrMid = (fontaddr & 0xff00) >> 8;
			addrLow = (fontaddr & 0xff);

			OLED_get_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 32);
			OLED_Display_16x16(x, y, fontbuf);
			x += 16;
			i += 2;
		}
		else if ((text[i] >= 0xa1) && (text[i] <= 0xa3) && (text[i + 1] >= 0xa1))
		{

			fontaddr = (text[i] - 0xa1) * 94;
			fontaddr += (text[i + 1] - 0xa1);
			fontaddr = fontaddr * 32;

			addrHigh = (fontaddr & 0xff0000) >> 16;
			addrMid = (fontaddr & 0xff00) >> 8;
			addrLow = (fontaddr & 0xff);

			OLED_get_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 32);
			OLED_Display_16x16(x, y, fontbuf);
			x += 16;
			i += 2;
		}
		else if ((text[i] >= 0x20) && (text[i] <= 0x7e))
		{
			unsigned char fontbuf[16];
			fontaddr = (text[i] - 0x20);
			fontaddr = (unsigned long)(fontaddr * 16);
			fontaddr = (unsigned long)(fontaddr + 0x3cf80);

			addrHigh = (fontaddr & 0xff0000) >> 16;
			addrMid = (fontaddr & 0xff00) >> 8;
			addrLow = fontaddr & 0xff;

			OLED_get_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 16);
			OLED_Display_8x16(x, y, fontbuf);
			x += 8;
			i += 1;
		}
		else
			i++;
	}
}

void OLED_Display_string_5x7(uint8_t x, uint8_t y, uint8_t *text)
{
	uint8_t i = 0;
	uint8_t addrHigh, addrMid, addrLow;
	while (text[i] > 0x00)
	{
		if ((text[i] >= 0x20) && (text[i] <= 0x7e))
		{
			uint8_t fontbuf[8];
			fontaddr = (text[i] - 0x20);
			fontaddr = (unsigned long)(fontaddr * 8);
			fontaddr = (unsigned long)(fontaddr + 0x3bfc0);

			addrHigh = (fontaddr & 0xff0000) >> 16;
			addrMid = (fontaddr & 0xff00) >> 8;
			addrLow = fontaddr & 0xff;

			OLED_get_data_from_ROM(addrHigh, addrMid, addrLow, fontbuf, 8);
			OLED_Display_5x7(x, y, fontbuf);
			x += 6;
			i += 1;
		}
		else
			i++;
	}
}

void OLED_ShowNum(uint8_t x, uint8_t y, float num1, uint8_t len)
{
	uint8_t i;
	uint32_t t, num;
	x = x + len * 8 + 8;
	num = num1 * 100;
	OLED_Display_GB2312_string(x - 24, y, ".");
	for (i = 0; i < len; i++)
	{
		t = num % 10;
		num = num / 10;
		x -= 8;
		if (i == 2)
		{
			x -= 8;
		}
		switch (t)
		{
		case 0:
			OLED_Display_GB2312_string(x, y, "0");
			break;
		case 1:
			OLED_Display_GB2312_string(x, y, "1");
			break;
		case 2:
			OLED_Display_GB2312_string(x, y, "2");
			break;
		case 3:
			OLED_Display_GB2312_string(x, y, "3");
			break;
		case 4:
			OLED_Display_GB2312_string(x, y, "4");
			break;
		case 5:
			OLED_Display_GB2312_string(x, y, "5");
			break;
		case 6:
			OLED_Display_GB2312_string(x, y, "6");
			break;
		case 7:
			OLED_Display_GB2312_string(x, y, "7");
			break;
		case 8:
			OLED_Display_GB2312_string(x, y, "8");
			break;
		case 9:
			OLED_Display_GB2312_string(x, y, "9");
			break;
		}
	}
}

void OLED_Init(void)
{
	IOInit(OLED_SCL_PIN, Mode_Out_PP);
	IOInit(OLED_SDA_PIN, Mode_Out_PP);
	IOInit(OLED_RES_PIN, Mode_Out_PP);
	IOInit(OLED_DC_PIN, Mode_Out_PP);
	IOInit(OLED_CS1_PIN, Mode_Out_PP);
	IOInit(OLED_CS2_PIN, Mode_Out_PP);
	IOInit(OLED_FS0_PIN, Mode_IPU);

	OLED_RES_Clr();
	DelayMs(200);
	OLED_RES_Set();

	OLED_WR_Byte(0xFD, OLED_CMD);
	OLED_WR_Byte(0x12, OLED_CMD);
	OLED_WR_Byte(0xAE, OLED_CMD); //--turn off oled panel
	OLED_WR_Byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
	OLED_WR_Byte(0xA0, OLED_CMD);
	OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3f, OLED_CMD); //--1/64 duty
	OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset Shift Mapping RAM Counter (0x00~0x3F)
	OLED_WR_Byte(0x00, OLED_CMD); //-not offset
	OLED_WR_Byte(0x40, OLED_CMD); //--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
	OLED_WR_Byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping     0xa0���ҷ��� 0xa1����
	OLED_WR_Byte(0xC8, OLED_CMD); //Set COM/Row Scan Direction   0xc0���·��� 0xc8����
	OLED_WR_Byte(0xDA, OLED_CMD); //--set com pins hardware configuration
	OLED_WR_Byte(0x12, OLED_CMD);
	OLED_WR_Byte(0x81, OLED_CMD); //--set contrast control register
	OLED_WR_Byte(0x7F, OLED_CMD); // Set SEG Output Current Brightness
	OLED_WR_Byte(0xD9, OLED_CMD); //--set pre-charge period
	OLED_WR_Byte(0x82, OLED_CMD); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
	OLED_WR_Byte(0xDB, OLED_CMD); //--set vcomh
	OLED_WR_Byte(0x34, OLED_CMD); //Set VCOM Deselect Level
	OLED_WR_Byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)
	OLED_WR_Byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)
	OLED_Clear();
	OLED_WR_Byte(0xAF, OLED_CMD);

	OLED_ColorTurn(0);
  OLED_DisplayTurn(0);
	OLED_Clear();
}
